跳到主要内容
Cowers://
全部文章
服务端与存储

FastAPI 请求全链路原理

从浏览器地址栏敲下回车,到页面显示结果,中间到底发生了什么。 这一篇讲原理;要查语法直接用 FastAPI 学习地图 的症状速查表;要系统学看讲义系列(从 01 HTTP 与 API 接口基础 开始)。

FastAPI 请求全链路原理

从浏览器地址栏敲下回车,到页面显示结果,中间到底发生了什么。 这一篇讲原理;要查语法直接用 FastAPI 学习地图 的症状速查表;要系统学看讲义系列(从 01 HTTP 与 API 接口基础 开始)。


一句话总览

浏览器访问:

http://127.0.0.1:8000/users/1

完整过程大概是:

浏览器

解析 URL

DNS 查询 IP

建立 TCP 连接

发送 HTTP 请求

服务器网卡收到数据

操作系统交给端口对应的进程

Uvicorn 接收请求

转换成 ASGI 请求

FastAPI 路由分发

执行你的 Python 函数

生成 HTTP 响应

通过 TCP 发回浏览器

浏览器解析响应并展示

一、浏览器输入网址后发生了什么

假设你访问:

http://127.0.0.1:8000/items/100?name=book

这个 URL 可以拆成:

部分 含义
http 协议
127.0.0.1 服务器地址
8000 端口
/items/100 路径
?name=book 查询参数

二、浏览器先确定“请求发给谁”

1. 如果是域名,需要 DNS 解析

比如:

https://www.example.com

浏览器不知道 www.example.com 是哪台机器,所以要查 DNS:

www.example.com → 93.184.216.34

DNS 的作用就是:

把域名翻译成 IP 地址。

如果是:

127.0.0.1
localhost

就不用真正去公网查 DNS。

127.0.0.1 表示:

本机

三、TCP 连接:浏览器和服务器建立通道

HTTP 请求不是直接“飞过去”的。

它通常跑在 TCP 连接上。

浏览器要先和服务器建立 TCP 连接:

浏览器: 我要连你
服务器: 可以连
浏览器: 好,开始通信

这就是常说的 TCP 三次握手

简化版:

浏览器 → 服务器:SYN
服务器 → 浏览器:SYN + ACK
浏览器 → 服务器:ACK

建立完成后,双方之间就有一条可靠的数据通道。


四、端口是什么

IP 找到的是一台机器。

端口找到的是这台机器上的某个程序。

比如你的电脑上:

程序 端口
FastAPI/Uvicorn 8000
MySQL 3306
PostgreSQL 5432
Redis 6379
SSH 22

所以:

127.0.0.1:8000

意思是:

本机上的 8000 端口对应的程序

你启动 FastAPI 时:

uvicorn main:app --reload

Uvicorn 默认监听:

127.0.0.1:8000

也就是:

操作系统收到发往 8000 端口的数据后,交给 Uvicorn 进程。

五、HTTP 请求长什么样

浏览器最终发出去的不是 Python 对象,而是一段文本格式的数据。

例如:

GET /items/100?name=book HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: Chrome
Accept: application/json

如果是 POST 请求,可能还会有请求体:

POST /users HTTP/1.1
Host: 127.0.0.1:8000
Content-Type: application/json
 
{
  "name": "Tom",
  "age": 18
}

HTTP 请求主要分成:

请求行
请求头
空行
请求体

例如:

GET /items/100?name=book HTTP/1.1     ← 请求行
Host: 127.0.0.1:8000                 ← 请求头
User-Agent: Chrome                   ← 请求头
 
                                      ← 空行
请求体                                ← GET 一般没有请求体

六、服务器机器收到请求后发生什么

请求到达服务器后,先不是 FastAPI 直接处理。

先经过:

网卡

操作系统内核

TCP/IP 协议栈

找到端口 8000

交给监听 8000 的进程

也就是:

Uvicorn

七、Uvicorn 是干什么的

FastAPI 本身不是直接监听端口的程序。

FastAPI 是一个 Web 框架。

真正负责监听端口、接收 TCP 数据、解析 HTTP 的是:

Uvicorn

你可以理解成:

Uvicorn = 服务器门卫 + HTTP 接收员
FastAPI = 后台业务系统
你的函数 = 具体办事的人

启动命令:

uvicorn main:app --reload

含义是:

找到 main.py 里的 app 对象
用 Uvicorn 启动它
监听 HTTP 请求

八、main:app 是什么意思

假设你有:

# main.py
from fastapi import FastAPI
 
app = FastAPI()

命令:

uvicorn main:app --reload

意思是:

main      → main.py 文件
app       → main.py 里的 app 变量
--reload  → 代码改动后自动重启

所以 Uvicorn 会加载:

from main import app

九、ASGI 是什么

FastAPI 不是直接和 Uvicorn 乱连的。

它们之间有一个规范,叫:

ASGI

ASGI 可以理解成:

Python Web 服务器和 Python Web 框架之间的通信标准。

也就是规定:

Uvicorn 收到请求后,应该用什么格式交给 FastAPI。
FastAPI 处理完后,应该用什么格式把响应交还给 Uvicorn。

所以整体关系是:

浏览器
  ↓ HTTP
Uvicorn
  ↓ ASGI
FastAPI

你的路由函数

十、FastAPI 内部怎么处理请求

假设代码是:

from fastapi import FastAPI
 
app = FastAPI()
 
@app.get("/items/{item_id}")
def get_item(item_id: int, name: str):
    return {
        "item_id": item_id,
        "name": name
    }

浏览器访问:

GET /items/100?name=book

FastAPI 会做这些事:

1. 接收 Uvicorn 传来的 ASGI 请求
2. 读取请求方法:GET
3. 读取请求路径:/items/100
4. 匹配路由:/items/{item_id}
5. 提取路径参数:item_id = "100"
6. 根据类型标注 int,把 "100" 转成 100
7. 读取查询参数:name = "book"
8. 调用你的函数:get_item(item_id=100, name="book")
9. 拿到返回值
10. 转成 JSON
11. 包装成 HTTP 响应
12. 交给 Uvicorn 发回浏览器

十一、路由分发细节

你写的:

@app.get("/items/{item_id}")
def get_item(item_id: int):
    return {"item_id": item_id}

相当于告诉 FastAPI:

如果收到 GET /items/某个值
就调用 get_item()

FastAPI 内部大概维护一张路由表:

请求方法 路径规则 函数
GET /items/{item_id} get_item
POST /users create_user
GET /users list_users

收到请求后:

GET /items/100

FastAPI 查表:

GET 匹配 GET
/items/100 匹配 /items/{item_id}
所以执行 get_item()

这就是路由分发。


十二、参数从哪里来

FastAPI 会根据函数参数自动判断参数来源。

1. 路径参数

@app.get("/items/{item_id}")
def get_item(item_id: int):
    return item_id

请求:

GET /items/100

来源:

item_id 来自 URL 路径

2. 查询参数

@app.get("/items")
def get_items(page: int = 1, size: int = 10):
    return {"page": page, "size": size}

请求:

GET /items?page=2&size=20

来源:

page=2
size=20

3. 请求体参数

from pydantic import BaseModel
 
class User(BaseModel):
    name: str
    age: int
 
@app.post("/users")
def create_user(user: User):
    return user

请求体:

{
  "name": "Tom",
  "age": 18
}

FastAPI 会把 JSON 转成:

User(name="Tom", age=18)

十三、FastAPI 为什么能自动校验类型

因为 FastAPI 读取了你的类型标注:

def get_item(item_id: int):

它知道:

item_id 应该是 int

如果请求:

GET /items/100

可以转成整数:

item_id = 100

如果请求:

GET /items/abc

不能转成整数,FastAPI 自动返回:

{
  "detail": [
    {
      "msg": "Input should be a valid integer"
    }
  ]
}

你的函数不会执行。

也就是说:

请求参数不合法

FastAPI 直接拦截

返回 422 错误

十四、你的函数执行完以后发生什么

比如:

@app.get("/items/{item_id}")
def get_item(item_id: int):
    return {
        "item_id": item_id,
        "name": "book"
    }

返回的是 Python 字典:

{
    "item_id": 100,
    "name": "book"
}

但是浏览器不能直接接收 Python 字典。

FastAPI 会把它转成 JSON:

{
  "item_id": 100,
  "name": "book"
}

然后包装成 HTTP 响应:

HTTP/1.1 200 OK
content-type: application/json
 
{
  "item_id": 100,
  "name": "book"
}

十五、HTTP 响应长什么样

HTTP 响应也分几部分:

状态行
响应头
空行
响应体

例如:

HTTP/1.1 200 OK
content-type: application/json
content-length: 29
 
{"item_id":100,"name":"book"}

状态码常见有:

状态码 含义
200 成功
201 创建成功
400 请求有问题
401 未登录
403 没权限
404 路由不存在
422 参数校验失败
500 服务器内部错误

十六、响应怎么回到浏览器

响应返回路线基本反过来:

你的函数

FastAPI 转 JSON

Uvicorn 转 HTTP 响应

操作系统 TCP 发送

网络传输

浏览器接收

浏览器解析响应

如果响应头是:

content-type: application/json

浏览器知道这是 JSON。

如果是:

content-type: text/html

浏览器就按 HTML 页面渲染。


十七、完整流程图

用户访问 URL

浏览器解析 URL

DNS:域名 → IP

TCP 三次握手,建立连接

浏览器构造 HTTP 请求

请求通过网络到服务器

服务器操作系统收到数据

根据端口交给 Uvicorn

Uvicorn 解析 HTTP

Uvicorn 按 ASGI 标准交给 FastAPI

FastAPI 查路由表

提取路径参数 / 查询参数 / 请求体

Pydantic 做类型转换和数据校验

执行你的路径操作函数

函数返回 Python 对象

FastAPI 转成 JSON 响应

Uvicorn 发回 HTTP 响应

浏览器收到响应

浏览器展示结果

十八、用一段 FastAPI 代码串起来

from fastapi import FastAPI
from pydantic import BaseModel
 
app = FastAPI()
 
class User(BaseModel):
    name: str
    age: int
 
@app.post("/users/{user_id}")
def update_user(user_id: int, user: User, token: str):
    return {
        "user_id": user_id,
        "name": user.name,
        "age": user.age,
        "token": token
    }

请求:

POST /users/10?token=abc123 HTTP/1.1
Host: 127.0.0.1:8000
Content-Type: application/json
 
{
  "name": "Tom",
  "age": 18
}

FastAPI 判断:

参数 来源
user_id 路径 /users/10
token 查询参数 ?token=abc123
user JSON 请求体

最终调用:

update_user(
    user_id=10,
    token="abc123",
    user=User(name="Tom", age=18)
)

返回:

{
  "user_id": 10,
  "name": "Tom",
  "age": 18,
  "token": "abc123"
}

十九、再压缩成一句核心理解

FastAPI 的完整请求处理可以记成:

浏览器发 HTTP 请求
→ Uvicorn 接收
→ ASGI 转交
→ FastAPI 路由分发
→ 参数解析和校验
→ 执行你的函数
→ 返回 JSON
→ Uvicorn 发回浏览器

最关键的是分清三层:

负责什么
Uvicorn 监听端口,接收 HTTP
ASGI Uvicorn 和 FastAPI 之间的通信规范
FastAPI 路由分发、参数校验、执行函数、生成响应

相关:FastAPI 学习地图 · 01 HTTP 与 API 接口基础 · 从项目学 FastAPI 全景笔记